package com.lazi.june.common.util;

import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

/**
 * desc: 基于Spring Cglib BeanCopier的 Bean 拷贝工具
 *
 * 优化点：
 * 1. 缓存 key 增加 converter 标记，避免错误复用
 * 2. 支持 Supplier 方式创建目标对象
 * 3. copyToList 优化，避免循环中多次查缓存
 * 4. 更清晰的异常信息
 *
 * @author huliqian
 * @since 2025/8/21
 */
public class BeanUtil {

    // 缓存 BeanCopier，避免重复创建
    private static final Map<String, BeanCopier> BEAN_COPIER_CACHE = new ConcurrentHashMap<>();

    private BeanUtil() {
        throw new UnsupportedOperationException("BeanUtil 是工具类，不可实例化");
    }

    /**
     * 拷贝源对象到目标对象（目标对象必须已存在）
     */
    public static void copyProperties(Object source, Object target) {
        copyWithConverter(source, target, null);
    }

    /**
     * 拷贝源对象到目标类，并返回一个新的目标对象（必须有无参构造函数）
     */
    public static <S, T> T copyProperties(Object source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        Objects.requireNonNull(targetClass, "Target class 不能为 null");
        try {
            T target = targetClass.getDeclaredConstructor().newInstance();
            copyWithConverter(source, target, null);
            return target;
        } catch (Exception e) {
            throw new RuntimeException("创建目标对象失败: " + targetClass.getName(), e);
        }
    }

    /**
     * 拷贝源对象到目标对象，支持 Supplier 自定义实例化逻辑
     */
    public static <S, T> T copyProperties(Object source, Supplier<T> supplier) {
        if (source == null) {
            return null;
        }
        Objects.requireNonNull(supplier, "Supplier 不能为 null");
        T target = supplier.get();
        copyWithConverter(source, target, null);
        return target;
    }

    /**
     * 拷贝并支持自定义字段转换器（高级用法）
     */
    public static void copyWithConverter(Object source, Object target, Converter converter) {
        Objects.requireNonNull(target, "Target 对象不能为 null");
        if (source == null) {
            return;
        }
        BeanCopier copier = getBeanCopier(source.getClass(), target.getClass(), converter);
        copier.copy(source, target, converter);
    }

    /**
     * 拷贝源对象 List 到目标对象 List
     */
    public static <S, T> List<T> copyToList(List<S> sourceList, Class<T> targetClass) {
        if (sourceList == null || sourceList.isEmpty()) {
            return Collections.emptyList();
        }
        List<T> targetList = new ArrayList<>(sourceList.size());
        BeanCopier copier = getBeanCopier(sourceList.get(0).getClass(), targetClass, null);
        for (S source : sourceList) {
            if (source == null) {
                targetList.add(null);
                continue;
            }
            try {
                T target = targetClass.getDeclaredConstructor().newInstance();
                copier.copy(source, target, null);
                targetList.add(target);
            } catch (Exception e) {
                throw new RuntimeException("创建目标对象失败: " + targetClass.getName(), e);
            }
        }
        return targetList;
    }

    private static BeanCopier getBeanCopier(Class<?> sourceClass, Class<?> targetClass, Converter converter) {
        String cacheKey = generateCacheKey(sourceClass, targetClass, converter != null);
        return BEAN_COPIER_CACHE.computeIfAbsent(cacheKey,
                k -> BeanCopier.create(sourceClass, targetClass, converter != null));
    }

    private static String generateCacheKey(Class<?> sourceClass, Class<?> targetClass, boolean useConverter) {
        return sourceClass.getName() + "->" + targetClass.getName() + (useConverter ? ":converter" : "");
    }
}
